package com.gzc.just.play.last.war.sceneserver.gameobject.base;

import com.gzc.just.play.last.war.sceneserver.gameobject.unit.GameUnit;
import com.gzc.just.play.last.war.sceneserver.gameobject.unit.GameUnitListener;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.UUID;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

/**
 * GameObject类的单元测试
 * 
 * @author AI Assistant
 * @version 1.0.0
 * @since 2025-11-25
 */
@ExtendWith(MockitoExtension.class)
@DisplayName("游戏对象基类测试")
class GameObjectTest {

    private TestGameObject gameObject;
    
    @BeforeEach
    void setUp() {
        gameObject = new TestGameObject(12345L, GameObjectType.HERO, GameObjectCamp.TEAM_1);
    }
    
    @Test
    @DisplayName("测试对象创建和基本属性")
    void testGameObjectCreation() {
        // 验证基本属性
        assertEquals(12345L, gameObject.getObjectId());
        assertEquals(GameObjectType.HERO, gameObject.getObjectType());
        assertEquals(GameObjectCamp.TEAM_1, gameObject.getCamp());
        assertNotNull(gameObject.getObjectUUID());
        
        // 验证初始状态
        assertFalse(gameObject.isActive());
        assertFalse(gameObject.isDestroyed());
        assertTrue(gameObject.isVisible());
        assertEquals(0L, gameObject.getMasterGuid());
        assertEquals(1000L, gameObject.getVisibilityRange());
        
        // 验证初始位置
        assertEquals(0.0, gameObject.getPosX(), 0.001);
        assertEquals(0.0, gameObject.getPosY(), 0.001);
        assertEquals(0.0, gameObject.getPosZ(), 0.001);
        
        // 验证初始方向
        assertEquals(0.0f, gameObject.getDirectionX(), 0.001f);
        assertEquals(0.0f, gameObject.getDirectionY(), 0.001f);
        assertEquals(0.0f, gameObject.getDirectionZ(), 0.001f);
        
        // 验证时间戳
        assertTrue(gameObject.getCreateTime() > 0);
        assertEquals(gameObject.getCreateTime(), gameObject.getLastUpdateTime());
    }
    
    @Test
    @DisplayName("测试位置相关操作")
    void testPositionOperations() {
        // 设置新位置
        Position newPos = new Position(100.0, 200.0, 300.0);
        gameObject.setPosition(newPos);
        
        // 验证位置已更新
        assertEquals(100.0, gameObject.getPosX(), 0.001);
        assertEquals(200.0, gameObject.getPosY(), 0.001);
        assertEquals(300.0, gameObject.getPosZ(), 0.001);
        assertEquals(newPos, gameObject.getPosition());
        
        // 验证更新时间已更新（应该大于等于创建时间）
        assertTrue(gameObject.getLastUpdateTime() >= gameObject.getCreateTime());
        
        // 测试位置获取
        Position retrievedPos = gameObject.getPosition();
        assertEquals(100.0, retrievedPos.getX(), 0.001);
        assertEquals(200.0, retrievedPos.getY(), 0.001);
        assertEquals(300.0, retrievedPos.getZ(), 0.001);
    }
    
    @Test
    @DisplayName("测试方向相关操作")
    void testDirectionOperations() {
        // 设置新方向
        Vector3 newDir = new Vector3(0.5f, 0.0f, 0.5f);
        gameObject.setDirection(newDir);
        
        // 验证方向已更新
        assertEquals(0.5f, gameObject.getDirectionX(), 0.001f);
        assertEquals(0.0f, gameObject.getDirectionY(), 0.001f);
        assertEquals(0.5f, gameObject.getDirectionZ(), 0.001f);
        assertEquals(newDir, gameObject.getDirection());
    }
    
    @Test
    @DisplayName("测试对象生命周期")
    void testLifecycle() {
        // 初始状态
        assertFalse(gameObject.isAlive());
        assertFalse(gameObject.isDestroyed());
        assertFalse(gameObject.isActive());
        
        // 激活对象
        gameObject.activate();
        assertTrue(gameObject.isActive());
        assertTrue(gameObject.isAlive());
        assertFalse(gameObject.isDestroyed());
        long activatedTime = gameObject.getLastUpdateTime();
        
        // 停用对象
        try {
            Thread.sleep(10); // 确保时间差
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        gameObject.deactivate();
        assertFalse(gameObject.isActive());
        assertFalse(gameObject.isAlive());
        assertFalse(gameObject.isDestroyed());
        assertTrue(gameObject.getLastUpdateTime() > activatedTime);
        
        // 销毁对象
        gameObject.destroy();
        assertFalse(gameObject.isActive());
        assertFalse(gameObject.isAlive());
        assertTrue(gameObject.isDestroyed());
    }
    
    @Test
    @DisplayName("测试可见性操作")
    void testVisibility() {
        // 初始状态
        assertTrue(gameObject.isVisible());
        
        // 设置不可见
        gameObject.setVisible(false);
        assertFalse(gameObject.isVisible());
        
        // 设置可见
        gameObject.setVisible(true);
        assertTrue(gameObject.isVisible());
        
        // 测试可见范围
        assertEquals(1000L, gameObject.getVisibilityRange());
        gameObject.setVisibilityRange(500L);
        assertEquals(500L, gameObject.getVisibilityRange());
    }
    
    @Test
    @DisplayName("测试主人GUID操作")
    void testMasterGuid() {
        // 初始状态
        assertEquals(0L, gameObject.getMasterGuid());
        
        // 设置主人GUID
        gameObject.setMasterGuid(99999L);
        assertEquals(99999L, gameObject.getMasterGuid());
        
        // 清除主人GUID
        gameObject.setMasterGuid(0L);
        assertEquals(0L, gameObject.getMasterGuid());
    }
    
    @Test
    @DisplayName("测试距离计算")
    void testDistanceCalculation() {
        // 创建另一个对象
        GameObject other = new TestGameObject(54321L, GameObjectType.NPC, GameObjectCamp.NEUTRAL);
        other.setPosX(3.0);
        other.setPosY(4.0);
        other.setPosZ(0.0);  // 3-4-5 三角形
        
        // 计算距离
        double distance = gameObject.getDistance(other);
        assertEquals(5.0, distance, 0.001);
        
        // 测试自身距离（应为0）
        assertEquals(0.0, gameObject.getDistance(gameObject), 0.001);
    }
    
    @Test
    @DisplayName("测试调试字符串")
    void testDebugString() {
        String debugString = gameObject.getDebugString();
        
        // 验证字符串包含关键信息
        assertTrue(debugString.contains("id=12345"));
        assertTrue(debugString.contains("type=HERO"));
        assertTrue(debugString.contains("camp=TEAM_1"));
        assertTrue(debugString.contains("pos=(0.000000,0.000000,0.000000)"));
        assertTrue(debugString.contains("active=false"));
        assertTrue(debugString.contains("destroyed=false"));
        
        // toString应返回调试字符串
        assertEquals(debugString, gameObject.toString());
    }
    
    @Test
    @DisplayName("测试心跳处理")
    void testHeartbeat() {
        long currentTime = System.currentTimeMillis();
        long deltaTime = 100;
        
        // 初始对象未激活，心跳不应产生任何效果
        gameObject.processHeartbeat(currentTime, deltaTime);
        
        // 激活对象后再处理心跳
        gameObject.activate();
        gameObject.processHeartbeat(currentTime + 100, deltaTime);
        
        // 测试对象会更新自己的lastUpdateTime
        assertEquals(currentTime + 100, gameObject.getLastUpdateTime());
    }
    
    /**
     * 测试用的GameObject具体实现类
     */
    private static class TestGameObject extends GameObject {
        private boolean initialized = false;
        
        public TestGameObject(long objectId, GameObjectType objectType, GameObjectCamp camp) {
            super(objectId, objectType, camp);
        }
        
        @Override
        public void initialize() {
            initialized = true;
        }
        
        @Override
        public void destroy() {
            super.setDestroyed(true);
        }
        
        @Override
        public void processHeartbeat(long currentTime, long deltaTime) {
            if (isAlive()) {
                setLastUpdateTime(currentTime);
            }
        }
        
        public boolean isInitialized() {
            return initialized;
        }
    }
}